package org.common.utils.rpc;

import org.common.utils.net.netty.NettyClient;
import org.common.utils.rpc.core.*;
import org.common.utils.rpc.entity.Host;
import org.common.utils.rpc.generator.GeneratorImplement;
import org.common.utils.rpc.net.RpcNettyDeCode;
import org.common.utils.rpc.net.RpcNettyEnCode;
import org.common.utils.rpc.net.RpcNettyInitializer;
import org.common.utils.rpc.net.handler.RpcClientNettyHandler;
import org.common.utils.rpc.net.serialization.RpcFurySerialization;
import org.common.utils.rpc.net.serialization.RpcSerialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;

/**
 * RPC客户端
 * @author zhouzhibing
 * @date 2025/11/14 23:12
 */
public class RpcClient {

    private static final Logger log = LoggerFactory.getLogger(RpcClient.class);
    /**
     * 连接对象
     */
    private final RpcConnection rpcConnection;
    /**
     * 消息池
     */
    private final RpcRequestPool requestPool;
    /**
     * Rpc初始化器
     */
    private final RpcNettyInitializer initializer;
    /**
     * 生成实现类
     */
    private final GeneratorImplement generatorImplement;
    /**
     * RpcClient额外所用到的参数列表
     */
    private final Map<Key , Object> argMap;
    /**
     * RPC发送器
     */
    private final RpcSenders senders;

    /**
     * 创建RPC客户端，会根据服务列表，和默认的Fury序列化方式进行序列化。
     * @param packageName 包名
     * @param hosts 服务器列表
     */
    public RpcClient(String packageName ,List<Host> hosts, ScheduledExecutorService schedule) {
        this(packageName , new RpcFurySerialization() , hosts, schedule , new HashMap<>());
    }

    /**
     * 创建RPC客户端，会根据服务列表，和默认的Fury序列化方式进行序列化。
     * @param packageName 包名
     * @param hosts 服务器列表
     */
    public RpcClient(String packageName ,List<Host> hosts, ScheduledExecutorService schedule, Map<Key , Object> argMap) {
        this(packageName , new RpcFurySerialization() , hosts, schedule , argMap);
    }

    /**
     * 创建RPC客户端，会根据服务列表，和指定序列化方式进行序列化。
     * @param serializable 序列化方式
     * @param hosts 服务器列表
     */
    public RpcClient(String packageName , RpcSerialization serializable , List<Host> hosts, ScheduledExecutorService schedule, Map<Key , Object> argMap) {
        Objects.requireNonNull(serializable);
        Objects.requireNonNull(hosts);
        Objects.requireNonNull(schedule);
        this.requestPool = new RpcRequestPool(schedule);
        this.rpcConnection = new RpcConnection();
        this.senders = new RpcSenders(rpcConnection , requestPool);
        this.generatorImplement = new GeneratorImplement();
        this.argMap = argMap;

        // 初始RPC初始化器
        Executor executor = (Executor)argMap.get(RpcClient.Key.HANDLER_EXECUTOR);
        RpcNettyEnCode enCode = new RpcNettyEnCode(serializable);
        RpcNettyDeCode deCode = new RpcNettyDeCode(serializable);
        RpcClientNettyHandler handler = new RpcClientNettyHandler(requestPool , executor);
        this.initializer = new RpcNettyInitializer(Const.CLIENT_NAME, enCode, deCode, handler);

        // 初始化客户端
        initClient(hosts);
        // 初始化实现类
        initImplement(packageName);
    }

    /**
     * 初始化实现类
     * @param packageName 包名
     */
    private void initImplement(String packageName) {
        Object saveGeneratorFile = argMap.get(Key.SAVE_GENERATOR_FILE);
        this.generatorImplement.saveGeneratorFile(saveGeneratorFile != null);
        this.generatorImplement.generator(senders, packageName);
    }

    /**
     * 初始化客户端
     * @param hosts 服务器列表
     */
    private void initClient(List<Host> hosts) {
        for (Host host : hosts) {
            NettyClient client = new NettyClient(initializer , host.getHost() , host.getPort());
            client.setAttach(new RpcAttach());
            rpcConnection.addClient(client);
        }
    }

    /**
     * 获取接口实现对象
     * @param clazz 接口类
     * @return 实现对象
     * @param <T> 接口类型
     */
    public <T> T getInterface(Class<T> clazz) {
        return generatorImplement.getImplement(clazz);
    }

    /**
     * 参数枚举类
     */
    public enum Key {
        /**
         * 保存生成类文件开关, 取值范围: [true|false]
         */
        SAVE_GENERATOR_FILE,
        /**
         * 处理执行器，主要用于Handler处理，取值范围: [Executor实现类]
         */
        HANDLER_EXECUTOR
    }
}
